from typing import Optional
from datetime import datetime

from fastapi import HTTPException

from src.database.models import (
    Weather,
    Weather_condition,
    Weather_to_forecast,
    Region
)
from src.region_service.schemas import Region_schema
from src.weather_service.schemas_weather import (
    Weather_record,
    Weather_to_forecast_schema,
    Weather_response_with_region_name
)

from src.database.my_crud import My_crud

from src.user_service.service.auth import raise_401_error

weather_crud = My_crud(Weather)
weather_condition_crud = My_crud(Weather_condition)
weather_to_forecast_crud = My_crud(Weather_to_forecast)
region_crud = My_crud(Region)


class Search_service:
    async def __raise_condition(self, condition: Optional[str]):
        if condition is None:
            return None

        if not await weather_condition_crud.exist(
            [Weather_condition.condition == condition]
        ):
            raise HTTPException(status_code=400, detail="bad condition")

    async def search_weather(
        self,
        startDateTime: Optional[datetime],
        endDateTime: Optional[datetime],
        regionId: Optional[int],
        weatherCondition: Optional[str],
        from_var: Optional[int],
        size: Optional[int],
        user_id: Optional[int]
    ):
        await raise_401_error(user_id)
        if weatherCondition:
            await self.__raise_condition(weatherCondition)

        where_filters = []
        if weatherCondition:
            where_filters.append(Weather.weatherCondition == weatherCondition)
        if startDateTime:
            where_filters.append(Weather.measurementDateTime >= startDateTime)
        if endDateTime:
            where_filters.append(Weather.measurementDateTime <= endDateTime)

        filters = []
        if regionId:
            filters.append(Weather.regionId == regionId)

        weather_records = await weather_crud.get(
            filters=filters,
            Output_model=Weather_record,
            where_filters=where_filters,
            offset=from_var,
            limit=size,
            multi=True
        )

        result = []
        for weather_record in weather_records:
            relations = await weather_to_forecast_crud.get(
                filters=[Weather_to_forecast.weatherId == weather_record.id],
                Output_model=Weather_to_forecast_schema,
                multi=True
            )

            weatherForecasts = [relation.weatherForecast for relation in relations]

            regionName = (await region_crud.get(
                filters=[Region.id == weather_record.regionId],
                Output_model=Region_schema
            )).name

            result.append(
                Weather_response_with_region_name(
                    regionName=regionName,
                    weatherForecast=weatherForecasts,
                    **weather_record.__dict__
                )
            )
        return result
